{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# music21: A Toolkit for Comupter-Aided Musicology"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Some examples to test basic music21 functionalities"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is a Jupyter notebook created by [@musicenfanthen](https://github.com/musicEnfanthen) and [@aWilsonandmore](https://github.com/aWilsonandmore) to work with some basic functionalities of music21 (http://web.mit.edu/music21/). For more information on Jupyter notebooks go to http://jupyter.org/. \n",
    "\n",
    "To execute a block of code in this notebook, click in the cell and press `Shift+Enter`.\n",
    "\n",
    "To get help on any music21 routine, click on it and press `Shift+Tab`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Imports and setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To use music21 in this notebook and python, you have to import all (\\*) routines  from music21 at first with the following command.\n",
    "\n",
    "<div class=\"alert alert-block alert-warning\">\n",
    "\"You’ll probably get a few warnings that you’re missing some optional modules. That’s okay. If you get a warning that “no module named music21” then something probably went wrong above.\" (Source: http://web.mit.edu/music21/doc/usersGuide/usersGuide_01_installing.html)\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from music21 import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Probably you have to set manually the correct file path to an Application that is able to open MusicXML files (like MuseScore). To do so, use the `music21.environment` module to set an `musicxmlPath` key.\n",
    "\n",
    "Make sure to change the string `path/to/your/musicXmlApplication` below to the correct file path (keep the quotation marks):\n",
    "- on Mac e.g.: `/Applications/MuseScore 2.app/Contents/MacOS/mscore` \n",
    "- or on Windows e.g.: `C:/Program Files (x86)/MuseScore 2/bin/MuseScore.exe`\n",
    "\n",
    "and uncomment the line (remove the `#` at the begin of the line).\n",
    "\n",
    "In the same way, you can also add a path to your lilypond installation, using\n",
    "`env['lilypondPath']`:\n",
    "- on Mac e.g.: `Applications/Lilypond.app`\n",
    "- on Windows e.g.: `C:/Program Files (x86)/LilyPond/usr/bin/lilypond.exe`\n",
    "\n",
    "Sometimes it's also necessary to adapt the `musescoreDirectPNGPath`. Check if it corresponds to your museScore path."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "env = environment.Environment()\n",
    "# env['musicxmlPath'] = 'path/to/your/musicXmlApplication'\n",
    "# env['lilypondPath'] = 'path/to/your/lilypond'\n",
    "# env['musescoreDirectPNGPath'] = 'path/to/your/museScore'\n",
    "\n",
    "print('Environment settings:')\n",
    "print('musicXML:  ', env['musicxmlPath'])\n",
    "print('musescore: ', env['musescoreDirectPNGPath'])\n",
    "print('lilypond:  ', env['lilypondPath'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Let's create some notes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One possible way to create notes in music21 is to use the `Note()`-Object (CAPITAL LETTER) within music21's `note`-subModule (small letter).\n",
    "\n",
    "Let's use the twelve-tone row of Alban Berg's Violin Concerto (1935) as an example. Take care how the different octaves and accidentals are declared."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "note1 = note.Note(\"G3\")     # declaration of first note\n",
    "note2 = note.Note(\"B-3\")\n",
    "note3 = note.Note(\"D4\")\n",
    "note4 = note.Note(\"F#4\")\n",
    "note5 = note.Note(\"A4\")\n",
    "note6 = note.Note(\"C5\")\n",
    "note7 = note.Note(\"E5\")\n",
    "note8 = note.Note(\"G#5\")\n",
    "note9 = note.Note(\"B5\")\n",
    "note10 = note.Note(\"C#6\")\n",
    "note11 = note.Note(\"D#6\")\n",
    "note12 = note.Note(\"F6\")\n",
    "\n",
    "# combine the twelve notes in a row list\n",
    "bergRow = [note1, note2, note3, note4, note5, note6, note7, note8, note9, note10, note11, note12]\n",
    "bergRow    # output of bergRow (by just using the name of the variable)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can use `dir(MODULENAME)` to find out which objects any module contains at all (http://web.mit.edu/music21/doc/usersGuide/usersGuide_02_notes.html#usersguide-02-notes):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dir(note)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To iterate over every single item in a list, you can use a \"FOR\"-loop.\n",
    "\n",
    "Syntax (indentation matters here!):\n",
    "\n",
    "    for ITEM in LIST:    \n",
    "        do something with ITEM\n",
    "        ...\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for currentNote in bergRow:                                    # for every note in bergRow list do...\n",
    "    currentNote.duration.type = 'whole'                        # ... declare duration of a whole note\n",
    "    print(currentNote.duration, currentNote.nameWithOctave)    # ... output of note duration and name (using the print command)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create simple Streams"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Streams are fundamental objects in music21. Almost everything (`Score`, `Parts`, `Voices`, `Measures` a.o.) is organized in terms of this abstract data structure. An empty stream is created by using the `Stream()`-Object (CAPITAL LETTER) within music21's `stream`-subModule (small letter)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergStream = stream.Stream()        # create empty stream\n",
    "\n",
    "for currentNote in bergRow:         # iterate over every note in bergRow and ...\n",
    "    bergStream.append(currentNote)  # ... append current note to the stream\n",
    "\n",
    "bergStream.show('text')             # output of the stream (using the .show()-method with option 'text'; compare to output above)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can get the length of a stream, what is the number of items in it, with `len(STREAM)`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(bergStream)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "... or with just counting the Note-Elements (here you have to flatten the stream):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(bergStream.flat.getElementsByClass(note.Note))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But let's have a look at the stream now. Calling the `.show()`-method without any option will display a graphical visualisation of any music object via the musicxmlApplication defined in the environment at the beginning of this notebook.\n",
    "\n",
    "If you encounter problems here, make sure you have set the correct environment settings for `musicxmlPath` and `musescoreDirectPNGPath`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergStream.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also use further options to get the output as `pdf` or `png` via `lilypond`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergStream.show('lily.pdf')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergStream.show('lily.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You could also use music21.tinyNotation, \"a simple way of specifying single line melodies\" (http://web.mit.edu/music21/doc/moduleReference/moduleTinyNotation.html), to define the notes of the row:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergRowTiny = converter.parse(\"tinyNotation: G1 B- d f# a c' e' g'# b' c''# d''# f''\")\n",
    "bergRowTiny.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our `bergRowTiny` is also a stream because the tinyNotation converter created it automatically. But keep aware of the slightly different structure:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergRowTiny.show('text')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ok nice, but where is the analytical part?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "music21 provides a large amount of build-in analytical tools. To start right away, just let's get the ambitus of the row in the stream using the `.analyze()`-method (http://web.mit.edu/music21/doc/moduleReference/moduleStream.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergStream.analyze('ambitus')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But always keep a \"thinking\" eye on the results:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergStream.analyze('key')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The twelve-tone row of Berg's Violin Concerto is special because of its two major triads, two minor triads and a part of the whole tone scale. Let's separate these elements into new `Chord()`-Objects (part of `chord`-submodule):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# declare some variables as Chord()-Objects\n",
    "triad1 = chord.Chord()\n",
    "triad2 = chord.Chord()\n",
    "triad3 = chord.Chord()\n",
    "triad4 = chord.Chord()\n",
    "wtScale = chord.Chord()\n",
    "\n",
    "# iterate over the first three notes in the stream\n",
    "for currentNote in bergStream[0:3]:\n",
    "    triad1.add(currentNote)           # add the currentNote to the Chord()\n",
    "\n",
    "# ...\n",
    "for currentNote in bergStream[2:5]:\n",
    "    triad2.add(currentNote)\n",
    "\n",
    "# ...\n",
    "for currentNote in bergStream[4:7]:\n",
    "    triad3.add(currentNote)\n",
    "\n",
    "# ...\n",
    "for currentNote in bergStream[6:9]:\n",
    "    triad4.add(currentNote)\n",
    "\n",
    "# iterate over the last three notes in the stream\n",
    "for currentNote in bergStream[8:12]:\n",
    "    wtScale.add(currentNote)\n",
    "\n",
    "# output the 5 chords\n",
    "triad1.show()\n",
    "triad2.show()\n",
    "triad3.show()\n",
    "triad4.show()\n",
    "wtScale.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can recombine multiple Chords() within a new Chord()-Object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fullChord = chord.Chord([triad1, triad2, triad3, triad4, wtScale])\n",
    "\n",
    "fullChord.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also append the chords to a new Stream()-Object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# create empty stream\n",
    "chordsStream = stream.Stream()\n",
    "\n",
    "# append all the triads to the stream\n",
    "chordsStream.append(triad1);\n",
    "chordsStream.append(triad2);\n",
    "chordsStream.append(triad3);\n",
    "chordsStream.append(triad4);\n",
    "chordsStream.append(wtScale);\n",
    "\n",
    "chordsStream.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And you can add some analytical descriptions to the objects using the `.addLyric()`-method and different attributes (e.g. `pitchedCommonName`, `intervalVector`, `primeForm`, `forteClass`) of the chords:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# iterate over every chord in the stream, and ...\n",
    "for currentChord in chordsStream:\n",
    "    currentChord.addLyric(currentChord.pitchedCommonName)    # ... add triad name\n",
    "    currentChord.addLyric(currentChord.intervalVector)       # ... add interval vector\n",
    "    currentChord.addLyric(currentChord.primeForm)            # ... add prime form\n",
    "    currentChord.addLyric(currentChord.forteClass)           # ... add forte class\n",
    "\n",
    "chordsStream.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Highlighting certain parts (e.g. all Forte classes \"3-11A\" = minor chord or \"3-11B\" = major chord) is also possible (http://web.mit.edu/music21/doc/usersGuide/usersGuide_10_examples1.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for currentChord in chordsStream.recurse().getElementsByClass('Chord'):\n",
    "    if currentChord.forteClass == '3-11A':\n",
    "        currentChord.style.color = 'red'\n",
    "        for x in currentChord.derivation.chain():\n",
    "            x.style.color = 'blue'\n",
    "    if currentChord.forteClass == '3-11B':\n",
    "        currentChord.style.color = 'blue'\n",
    "        for x in currentChord.derivation.chain():\n",
    "            x.style.color = 'blue'\n",
    "\n",
    "chordsStream.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Introducing music21 the serial module"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Most (=all?) of the twelve tone rows by Schönberg, Berg and Webern are already incorporated into a dictionary list in music21. You get an sorted overview of the rows available in the dictionary with the following command: (http://web.mit.edu/music21/doc/moduleReference/moduleSerial.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sorted(list(serial.historicalDict))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For all these rows, music21 provides not only the pitches of the row, but some additional meta information. So let's see what we get with the 'RowBergViolinConcerto':"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergRowInternal = serial.getHistoricalRowByName('RowBergViolinConcerto')\n",
    "print(type(bergRowInternal))\n",
    "print(bergRowInternal.composer)\n",
    "print(bergRowInternal.opus)\n",
    "print(bergRowInternal.title)\n",
    "print(bergRowInternal.row)\n",
    "print(bergRowInternal.pitchClasses())\n",
    "bergRowInternal.noteNames()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Transformations\n",
    "\n",
    "Using the serial modules' '.originalCenteredTransformation()'-method, you can retrieve transformational forms of a ToneRow()-Object. \"Admissible transformations are ‘T’ (transposition), ‘I’ (inversion), ‘R’ (retrograde), and ‘RI’ (retrograde inversion).\" (http://web.mit.edu/music21/doc/moduleReference/moduleSerial.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "g = bergRowInternal.originalCenteredTransformation('T', 0)\n",
    "u = bergRowInternal.originalCenteredTransformation('I', 0)\n",
    "k = bergRowInternal.originalCenteredTransformation('R', 0)\n",
    "ku = bergRowInternal.originalCenteredTransformation('RI', 0)\n",
    "\n",
    "print('original:')\n",
    "g.show()\n",
    "\n",
    "print('inversion:')\n",
    "u.show()\n",
    "\n",
    "print('retrograde:')\n",
    "k.show()\n",
    "\n",
    "print('retrograde inversion:')\n",
    "ku.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 12-tone matrix \n",
    "\n",
    "You can also easily get the 12-tone matrix of a twelve tone row:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergMatrix1 = bergRowInternal.matrix()\n",
    "print(bergMatrix1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bergMatrix2 = serial.rowToMatrix(bergRowInternal.row)\n",
    "print(bergMatrix2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Segmentation\n",
    "\n",
    "One of the fundamental operations concerning the analysis of a twelve tone composition is segmentation. The following example provides a function, that iterates over a set of notes (`bergRowInternal`) and looks for every possible segment of a certain length (`segmentationSize`). Thus, per default, we iterate over every possible 3-tone segment of the Berg row."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "segmentationList = {}\n",
    "segmentationLength = 3     # here you can choose the length of the segments (try other values)\n",
    "\n",
    "rangeEnd = 12 - segmentationLength + 1\n",
    "\n",
    "\n",
    "# iterate over the whole tone row in (rangeEnd - 1) steps\n",
    "for i in range(0,rangeEnd):\n",
    "    print('---')\n",
    "    # create an empty placeholder for the segment as a ToneRow()-Object \n",
    "    # at the position i in the segmentationList\n",
    "    segmentationList[i] = serial.ToneRow()\n",
    "    \n",
    "    # fill up the segment with the corresponding notes\n",
    "    for currentNote in bergRowInternal[i:i+segmentationLength]:\n",
    "        segmentationList[i].append(currentNote)\n",
    "    print('Run ', i, ' completed.')     # This is for control only.\n",
    "    \n",
    "segmentationList     # output of the whole list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have every possible 3-tone segment of the Berg row, we can check if there are any triads in it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# check for triads in the segmentation list\n",
    "# make sure to use segmentLength = 3 above \n",
    "# (for segmentLength = 4 you will get 7th and other tetra chords)\n",
    "\n",
    "for i in segmentationList:\n",
    "    print('---')\n",
    "    print('RUN ', i)\n",
    "    outputString = ''\n",
    "    \n",
    "    # get a list of the pitches of the current segment\n",
    "    currentPitchList = segmentationList[i].pitches\n",
    "    print(currentPitchList)\n",
    "    \n",
    "    #use the pitchList as input for a chord\n",
    "    currentChord = chord.Chord(currentPitchList)\n",
    "    \n",
    "    # check for minor triad (with highlighting)\n",
    "    # use forteClass 3-11A instead of 'isMinorTriad()'-method to catch enharmonic equivalents\n",
    "    if currentChord.forteClass == '3-11A':        \n",
    "        currentChord.style.color = 'red'\n",
    "        outputString = 'MINOR TRIAD: '\n",
    "    \n",
    "    # check for major triad (with highlighting)\n",
    "    # use forteClass 3-11B instead of 'isMajorTriad()'-method to catch enharmonic equivalents\n",
    "    if currentChord.forteClass == '3-11B':\n",
    "        currentChord.style.color = 'blue'\n",
    "        outputString = 'MAJOR TRIAD: '\n",
    "    \n",
    "    currentChord.show()\n",
    "    \n",
    "    outputString += currentChord.pitchedCommonName\n",
    "    print(outputString)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "\n",
    "   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
